<?php

/**
 * Task Transforms the propel schema into a Dia compatible uncompressed UML
 *
 * @author  Gabor Kormany - <kormanyg@gmail.com>
 * @version 0.2.1
 */

class PropelToDiaTask extends sfPropelBaseTask
{
  // Default env options
  const DEFAULT_ENV_OPTION        = 'cli';
  const DEFAULT_DEBUG_OPTION      = true;

  // Default task options
  const DEFAULT_FILE_DIR_OPTION        = 'config';
  const DEFAULT_OUTPUT_DIR_OPTION      = '/config';
  const DEFAULT_PACKAGE_OPTION         = 'lib.model';
  const DEFAULT_EXTERNAL_TABLES_OPTION = '';

  /**
   * @see sfTask
   */
  protected function configure()
  {
    $this->addArguments(array(
      new sfCommandArgument( 'file', sfCommandArgument::REQUIRED, 'The file name'),
    ));


    $this->addOptions(array(
      new sfCommandOption( 'y', null, sfCommandOption::PARAMETER_OPTIONAL, 'Looks for yml(s) instead of xml(s)', 0 ),
    ));

    $this->namespace = 'propel';
    $this->name = 'propel-to-dia';
    $this->briefDescription = 'Transforms a schema xml to a Dia XML file';

    $this->detailedDescription = <<<EOF
The [propel:propel-to-dia|INFO] transforms a propel schema file into a Dia UML diagram.

The diagram will not be cleaned!

  Quick version:
  --> [./symfony propel:propel-to-dia schema.xml|INFO]

EOF;
  }

  /**
   * @see sfTask
   */
  protected function execute($arguments = array(), $options = array())
  {
    // Check parameters
    $this->setClassOptions($arguments, $options);
    $this->checkParameters();

    // 0 - Start
    $this->logSection('START', ' - Start time: '. $this->getCurrentDateTime() );

    // 1 - Conert schema files to xml
    if ( $options['y'] !== 0 )
    {
      $this->schemaToXML(self::DO_NOT_CHECK_SCHEMA, 'generated-');
      /** TODO: add support for displaying schema declared in plugins */
      //$this->copyXmlSchemaFromPlugins('generated-');
    }

    // 2 - Assemble xml files
    $this->assembleXMLs();

    // 3 - Convert schema to xml
    $this->doConvertSchema();
    $this->logSection('file+', sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.self::DEFAULT_FILE_DIR_OPTION.DIRECTORY_SEPARATOR.'db_model_alfa.dia created' );

    // 4 - if we had xml(s) from yml(s) remove them
    if ( $options['y'] !== 0 )
    {
      $this->cleanup();
    }

    // 4 - End
    $this->logSection('END', ' - End time: '. $this->getCurrentDateTime());
  }

  /**
   * Check parameters and raise at the first incorrect one.
   *
   * @return Exception
   */
  protected function checkParameters($arguments = array(), $options = array())
  {
    // Check xlst
    if (!class_exists('xsltprocessor'))
    {
      throw new Exception('PHP XSL extension must be installed and enabled on your system to use this task.');
    }
  }

  /**
   * Transforms the propel xml to Dia UML.
   */
  function doConvertSchema()
  {
    // DIA xsl
    $dia_transformation_file = dirname(__FILE__). '/../vendor/dia/dia-propel2uml.xsl';
    $path = sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.self::DEFAULT_FILE_DIR_OPTION.DIRECTORY_SEPARATOR;

    chdir( $path );

    // Load the XML source
    $xml = new DOMDocument;
    $xml->load( $path.'schema.xml' );

    $xsl = new DOMDocument;
    $xsl->load( $dia_transformation_file );

    // Configure the transformer
    $proc = new XSLTProcessor;
    $proc->importStyleSheet( $xsl ); // attach the xsl rules

    $result = $proc->transformToXML( $xml );

    chdir( sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR );

    $filesystem = $this->getFilesystem();
    $filesystem->touch( $this->file );
    @file_put_contents( $this->file, $result );
  }

  /**
   * Save xml schema.
   */
  public function writeSchema()
  {
    $filesystem = $this->getFilesystem();
    $filesystem->touch($this->output_path);
    @file_put_contents($this->output_path, $this->xmlstr);
    $this->log(' - Database xml schema saved.');
  }

  /**
  * Finds xml(s) in the config directory, and merges them into one schema.xml.
  *
  * TODO: it should use the functions defined in the base class...
  */
  protected function assembleXMLs()
  {
    $xml_transformation_file = dirname(__FILE__). '/../vendor/dia/table_extractor.xsl';
    $path = sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.self::DEFAULT_FILE_DIR_OPTION.DIRECTORY_SEPARATOR;
    $hDir = opendir( $path );

    $xsl = new DOMDocument;
    $xsl->load( $xml_transformation_file );

    // Configure the transformer
    $proc = new XSLTProcessor;
    $proc->importStyleSheet( $xsl ); // attach the xsl rules

    $result = "<?xml version='1.0' encoding='UTF-8'?>";
    $result .= "<database package='lib.model' name='propel' defaultIdMethod='native' noxsd='true'>";

    while( ( $filename = readdir( $hDir ) ) !== false )
    {
        if ( is_dir( $filename ) )
        {
        }
        else if ( strpos( $filename, "schema.xml" ) !== false && strpos( $filename, "schema-transformed.xml" ) === false )
        {
            // Load the XML source
            $xml = new DOMDocument;
            $xml->load( $path.$filename );
            $result .= preg_replace( '/\<\?.*\n/', '', $proc->transformToXML( $xml ) );

        }
    }
    $result .= "</database>";

    $filesystem = $this->getFilesystem();
    $filesystem->touch(  $path.'schema.xml' );
    @file_put_contents( $path.'schema.xml', $result );
    closedir( $hDir );
  }

  /**
   * Return current formated date time to check task length.
   *
   * @return String
   */
  protected function getCurrentDateTime()
  {
    return date('Y-m-d H:i:s');
  }

  /**
   * Assign options to class to make them available everywhere.
   */
  protected function setClassOptions($arguments = array(), $options = array())
  {
    if ( !preg_match( "/\.dia$/", $arguments['file'] ) )
      $arguments['file'] .= ".dia";

    $this->file = self::DEFAULT_FILE_DIR_OPTION.DIRECTORY_SEPARATOR.$arguments['file'];;
  }


  protected function cleanup()
  {
    if (is_null($this->commandApplication) || !$this->commandApplication->withTrace())
    {
      $finder = sfFinder::type('file')->name('/^(generated-)?.*schema(-transformed)?.xml$/');
      $this->getFilesystem()->remove($finder->in(array('config', 'plugins')));
    }
  }
}
